<template>
  <div>
    <div id="container"></div>
  </div>
</template>

<script>
import * as THREE from 'three'
import {OrbitControls} from "three/addons/controls/OrbitControls";

let scene;
export default {
  name: "bone-example",
  data() {
    return{
      camera:null,
      cameraCurve:null,
      renderer:null,
      container:null,
      controls:null,
      mesh:null,
      step: 0.1,
    }
  },
  methods:{
    initScene(){
      scene = new THREE.Scene();
      const axesHelper = new THREE.AxesHelper( 100 );
      axesHelper.position.set(0,0,0)
      scene.add( axesHelper );
    },
    initCamera(){
      this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
      this.camera.position.set(200,400,200);
    },
    initLight(){
      //添加两个平行光
      const directionalLight1 = new THREE.DirectionalLight(0xffffff, 1.5);
      directionalLight1.position.set(300,300,300)
      scene.add(directionalLight1);
      const directionalLight2 = new THREE.DirectionalLight(0xffffff, 1.5);
      directionalLight2.position.set(-300,300,300)
      scene.add(directionalLight2);
    },
    initBone(){
      // 圆柱体
      const geometry = new THREE.CylinderGeometry(2, 2, 40, 8, 12)
      const material = new THREE.MeshLambertMaterial({color:'#FCE6C9',metalness: 0.5,transparent: true, opacity:0.7});
      // 蒙皮 - 皮肤
      this.mesh = new THREE.SkinnedMesh(geometry, material)
      this.mesh.position.set(0,20,0)
      scene.add(this.mesh);
      // 首先，创建一个起点. 创建骨骼系统,
      let b1 = new THREE.Bone(); //b1作为根
      b1.position.set(0, -20, 0);
      let b2 = new THREE.Bone();//基于bone1的-20位置多10
      b1.add(b2)
      b2.position.set(0, 10, 0);//基于bone2的-10位置多10
      let b3 = new THREE.Bone();
      b2.add(b3)
      b3.position.set(0, 10, 0);//基于bone3的0位置多10
      let b4 = new THREE.Bone();
      b3.add(b4)
      b4.position.set(0, 10, 0);//基于bone4的10位置多10
      let b5 = new THREE.Bone();
      b4.add(b5)
      b5.position.set(0, 10, 0);//基于bone5的10位置多10,到达圆柱最顶部

      /* 这段代码作用是现实骨骼的节点，方便查看骨骼运动过程中节点的位置*/
      const group1 = new THREE.Group(); // 骨骼关节可以和普通网格模型一样作为其他模型子对象，添加到场景中
      group1.add(b1);
      const skeletonHelper = new THREE.SkeletonHelper(group1); // SkeletonHelper会可视化参数模型对象所包含的所有骨骼关节
      group1.add(skeletonHelper);
      scene.add(skeletonHelper);

      // 创建骨架
      const skeleton = new THREE.Skeleton([b1, b2, b3, b4, b5])
      this.mesh.add(b1)
      this.mesh.bind(skeleton)
      // 添加权重   设置的就是蒙皮的权重，  顶点的蒙皮索引
      const index = [] // 索引
      const weight = [] // 权重
      const arr = geometry.attributes.position.array;
      //设置模型每个节点受骨骼的影响程度，如果是已有的模型文件会有自带的权重，这里是个圆柱体需要手动设置
      for (let i = 0; i < arr.length; i += 3) {
        const y = arr[i + 1] + 20
        const weightValue = (y % 10) / 10
        index.push(Math.floor(y / 10), Math.floor(y / 10) + 1, 0, 0)
        weight.push(1 - weightValue, weightValue, 0, 0);
      }
      geometry.setAttribute('skinIndex', new THREE.Uint16BufferAttribute(index, 4));
      geometry.setAttribute('skinWeight', new THREE.Float32BufferAttribute(weight, 4));
    },
    initRenderer(){
      this.renderer = new THREE.WebGLRenderer({ antialias: true });
      this.container = document.getElementById("container")
      this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
      this.renderer.setClearColor('#AAAAAA', 1.0);
      this.container.appendChild(this.renderer.domElement);
    },
    initControl(){
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);
      this.controls.enableDamping = true;
      this.controls.maxPolarAngle = Math.PI / 2.2;      // // 最大角度
    },
    initAnimate() {
      requestAnimationFrame(this.initAnimate);
      this.renderer.render(scene, this.camera);
      // 添加边界，如果弯曲超过一定的幅度，就设置负值向另一侧弯曲
      if (this.mesh.skeleton.bones[0].rotation.x > 0.3 || this.mesh.skeleton.bones[0].rotation.x < -0.3 ) {
        this.step = -this.step
      }
      //修改骨骼关节的位置角度来实现动画效果
      for (let i = 0; i < this.mesh.skeleton.bones.length; i++) {
        this.mesh.skeleton.bones[i].position.x += this.step;
        this.mesh.skeleton.bones[i].rotation.x += this.step * Math.PI / 180;
      }
    },
    initPage(){
      this.initScene();
      this.initCamera();
      this.initLight();
      this.initRenderer();
      this.initControl();
      this.initBone();
      this.initAnimate();
    }
  },
  mounted() {
    this.initPage()
  }
}
</script>

<style scoped>
#container{
  position: absolute;
  width:100%;
  height:100%;
  overflow: hidden;
}

</style>
